/*
 *  This file is part of LifeBudget - Copyright 2010 Clifton Eaton
 *  ------------------------------------------------------------------
 *  LifeBudget is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  LifeBudget is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with LifeBudget.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.lifebudget.app.client.mvc.view.paycheck;

import java.util.ArrayList;
import java.util.List;

import org.lifebudget.app.client.events.AppEvents;
import org.lifebudget.app.client.misc.NumberFormatter;
import org.lifebudget.app.client.mvc.model.BMF;
import org.lifebudget.app.client.mvc.model.Category;
import org.lifebudget.app.client.mvc.model.CategoryAmount;
import org.lifebudget.app.client.mvc.model.PaycheckCalculator;
import org.lifebudget.app.client.mvc.model.PaycheckSummary;
import org.lifebudget.app.client.mvc.model.PaycheckCalculator.Interval;
import org.lifebudget.app.client.mvc.view.AppView;

import com.extjs.gxt.ui.client.Registry;
import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.Orientation;
import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.binding.Converter;
import com.extjs.gxt.ui.client.binding.FieldBinding;
import com.extjs.gxt.ui.client.binding.FormBinding;
import com.extjs.gxt.ui.client.binding.SimpleComboBoxFieldBinding;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.ChangeEvent;
import com.extjs.gxt.ui.client.data.ChangeListener;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.Events;
import com.extjs.gxt.ui.client.event.FieldEvent;
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.event.MessageBoxEvent;
import com.extjs.gxt.ui.client.event.SelectionChangedEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.mvc.AppEvent;
import com.extjs.gxt.ui.client.mvc.Controller;
import com.extjs.gxt.ui.client.mvc.Dispatcher;
import com.extjs.gxt.ui.client.mvc.View;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.store.Record;
import com.extjs.gxt.ui.client.store.StoreEvent;
import com.extjs.gxt.ui.client.store.StoreListener;
import com.extjs.gxt.ui.client.store.TreeStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.extjs.gxt.ui.client.widget.Text;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.ComboBox;
import com.extjs.gxt.ui.client.widget.form.FieldSet;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.NumberField;
import com.extjs.gxt.ui.client.widget.form.SimpleComboBox;
import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.form.ComboBox.TriggerAction;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.MarginData;
import com.extjs.gxt.ui.client.widget.layout.RowData;
import com.extjs.gxt.ui.client.widget.layout.RowLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.core.client.GWT;

/**
 * The Class PaycheckCalculatorEditorView provides the view
 * for editing a {@link PaycheckCalculator}.  The editor can edit the 
 * details of the PaycheckCalculator as well as managing the associated 
 * {@link CategoryAmount} objects.
 */
public class PaycheckCalculatorEditorView extends View {

	/** The center. */
	private LayoutContainer center;
	
	/** The content. */
	private LayoutContainer content;
	
	/** The category amount form bindings. */
	private FormBinding categoryAmountFormBindings;
	
	/** The category amount store. */
	private ListStore<BeanModel> categoryAmountStore;
	
	/** The paycheck details form bindings. */
	private FormBinding paycheckDetailsFormBindings;
	
	/** The paycheck details store. */
	private TreeStore<PaycheckCalculator> paycheckDetailsStore;
	
	/** The paycheck calc. */
	private PaycheckCalculator paycheckCalc;
	
	/** The category amounts grid. */
	private Grid<BeanModel> categoryAmountsGrid;
	
	/** The category combo box. */
	private ComboBox<BeanModel> categoryComboBox;
	
	/** The category amount field. */
	private NumberField categoryAmountField;
	
	/** The name field. */
	private TextField<String> nameField;
	
	/** The estimated amount field. */
	private NumberField estimatedAmountField;
	
	/** The interval combo box. */
	private SimpleComboBox<String> intervalComboBox;
	
	/** The description field. */
	private TextArea descriptionField;
	
	/** The add category amount button. */
	private Button addCategoryAmountButton;
	
	/** The delete category amount button. */
	private Button deleteCategoryAmountButton;

	/**
	 * Instantiates a new paycheck calculator editor view.
	 *
	 * @param controller the controller
	 */
	public PaycheckCalculatorEditorView(Controller controller) {
		super(controller);
	}

	/**
	 * Handles the <code>PaycheckListLoaded</code> event.  This is 
	 * essentially the initialization method since we are dependent on the 
	 * Paycheck Calculator List being loaded first.
	 *
	 * @param event the <code>PaycheckListLoaded</code> event
	 */
	private void onPaycheckListLoaded(AppEvent event) {
		// //GWT.log("Initializing PCEV");
		paycheckDetailsStore = (TreeStore<PaycheckCalculator>) Registry.get(PaycheckCalculatorView.PAYCHECK_CALC_STORE);

		allCategoriesStore = new ListStore<BeanModel>();
		List<Category> categories = event.getData();
		populateAllCategoriesStore(categories);

		content = Registry.get(PaycheckCalculatorView.PAYCHECK_CALC_EDITOR_VIEW_CONTAINER);
		center = Registry.get(AppView.CENTER_PANEL);

		content.add(assembleCenter());
		disableForm();
		center.layout();

	}

	/**
	 * Populate all categories store.
	 *
	 * @param categories the categories
	 */
	private void populateAllCategoriesStore(List<Category> categories) {
		// for initializing the dropdown

		List<BeanModel> allCategories = BMF.getCategoryFactory().createModel(categories);
		if (categoryAmountFormBindings != null) {
			categoryAmountFormBindings.unbind();
		}
		allCategoriesStore.removeAll();
		allCategoriesStore.add(allCategories);
	}

	/**
	 * Disable form.
	 */
	private void disableForm() {
		nameField.disable();
		descriptionField.disable();
		estimatedAmountField.disable();
		descriptionField.disable();
		disableCategoryAmountForm();
		intervalComboBox.disable();
		categoryAmountsGrid.disable();
		addCategoryAmountButton.disable();
		deleteCategoryAmountButton.disable();
	}

	/**
	 * Disable category amount form.
	 */
	private void disableCategoryAmountForm() {
		categoryAmountField.disable();
		categoryComboBox.disable();
	}

	/**
	 * Enable form.
	 */
	private void enableForm() {
		nameField.enable();
		descriptionField.enable();
		estimatedAmountField.enable();
		descriptionField.enable();
		if (!categoryAmountStore.getModels().isEmpty()
				&& !categoryAmountsGrid.getSelectionModel().getSelectedItems().isEmpty()) {
			enableCategoryAmountForm();
		} else {
			disableCategoryAmountForm();
		}
		intervalComboBox.enable();
		categoryAmountsGrid.enable();
		addCategoryAmountButton.enable();
		deleteCategoryAmountButton.enable();

	}

	/**
	 * Enable category amount form.
	 */
	private void enableCategoryAmountForm() {
		categoryAmountField.enable();
		categoryComboBox.enable();
	}

	/**
	 * Assemble center.
	 *
	 * @return the layout container
	 */
	private LayoutContainer assembleCenter() {
		RowLayout rowLayout = new RowLayout(Orientation.VERTICAL);
		LayoutContainer editorContainer = new LayoutContainer(rowLayout);

		ContentPanel paycheckDetailsPanel = createPaycheckDetailsPanel();

		ContentPanel categoryAmountPanel = createCategoryAmountsPanel();

		editorContainer.add(paycheckDetailsPanel, new RowData(1, .5));
		editorContainer.add(categoryAmountPanel, new RowData(1, .5));
		return editorContainer;
	}

	/**
	 * Creates the paycheck details panel.
	 *
	 * @return the content panel
	 */
	private ContentPanel createPaycheckDetailsPanel() {
		ContentPanel paycheckDetailsPanel = new ContentPanel();
		paycheckDetailsPanel.setHeading("Details");
		paycheckDetailsPanel.setFrame(false);
		FieldSet paycheckDetailsForm = createPaycheckDetailsForm();
		paycheckDetailsPanel.add(paycheckDetailsForm, new MarginData(5));
		return paycheckDetailsPanel;
	}

	/**
	 * Creates the category amounts panel.
	 *
	 * @return the content panel
	 */
	private ContentPanel createCategoryAmountsPanel() {

		ContentPanel categoryAmountsPanel = new ContentPanel();
		categoryAmountsPanel.setHeading("Category Amounts");
		categoryAmountsPanel.setFrame(false);
		categoryAmountsPanel.setLayout(new FitLayout());

		// row Widget layout container
		RowLayout rLayout = new RowLayout(Orientation.HORIZONTAL);

		LayoutContainer rowLayoutContainer = new LayoutContainer(rLayout);
		// rowWidget.setSize(850, 350);

		categoryAmountsGrid = createCategoryAmountsGrid();

		FormPanel panel = createCategoryAmountForm();
		FieldSet fs = new FieldSet();
		fs.add(panel);
		fs.setHeading("Category Amount");

		rowLayoutContainer.add(categoryAmountsGrid, new RowData(.40, 1));
		rowLayoutContainer.add(new Text(), new RowData(.01, 1));
		rowLayoutContainer.add(fs, new RowData(.59, 1));

		// Create buttons on the contentpanel
		createCategoryAmountsPanelButtons(categoryAmountsPanel, categoryAmountsGrid);

		if (categoryAmountStore.getModels().isEmpty()) {
			deleteCategoryAmountButton.disable();
		}

		// categoryAmountsPanel.add(hLayoutContainer);
		categoryAmountsPanel.add(rowLayoutContainer);
		return categoryAmountsPanel;
	}

	/**
	 * Creates the category amounts panel buttons.
	 *
	 * @param categoryAmountsPanel the category amounts panel
	 * @param grid the grid
	 */
	private void createCategoryAmountsPanelButtons(ContentPanel categoryAmountsPanel, final Grid<BeanModel> grid) {
		categoryAmountsPanel.setButtonAlign(HorizontalAlignment.CENTER);

		// Create Toolbar
		ToolBar toolBar = new ToolBar();
		addCategoryAmountButton = new Button("Add");
		deleteCategoryAmountButton = new Button("Delete");
		addCategoryAmountButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleAddCategoryAmountButtonClicked();
			}

		});
		deleteCategoryAmountButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				handleDeleteCategoryAmountButtonClicked();
			}

		});

		toolBar.add(addCategoryAmountButton);
		toolBar.add(deleteCategoryAmountButton);
		categoryAmountsPanel.setTopComponent(toolBar);

		categoryAmountsPanel.addButton(new Button("Reset", new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				handlePaycheckCalcResetButtonClicked(grid);
			}

		}));
		categoryAmountsPanel.addButton(new Button("Commit", new SelectionListener<ButtonEvent>() {
			@Override
			public void componentSelected(ButtonEvent ce) {
				handlePaycheckCalcCommitButtonClicked(grid);
			}

		}));
	}

	/**
	 * Handle paycheck calc commit button clicked.
	 *
	 * @param grid the grid
	 */
	private void handlePaycheckCalcCommitButtonClicked(final Grid<BeanModel> grid) {
		grid.getStore().commitChanges();
		paycheckDetailsStore.commitChanges();
	}

	/**
	 * Handle paycheck calc reset button clicked.
	 *
	 * @param grid the grid
	 */
	private void handlePaycheckCalcResetButtonClicked(final Grid<BeanModel> grid) {
		categoryAmountStore.rejectChanges();
		List<BeanModel> models = categoryAmountStore.getModels();
		for (BeanModel beanModel : models) {
			if ((Long) beanModel.get("id") == 0) {
				categoryAmountStore.remove(beanModel);
			}
		}
		paycheckDetailsStore.rejectChanges();

		updatePaycheckSummary();
	}

	/**
	 * Handle delete category amount button clicked.
	 */
	protected void handleDeleteCategoryAmountButtonClicked() {
		final BeanModel cabm = categoryAmountsGrid.getSelectionModel().getSelectedItem();
		final CategoryAmount ca = (CategoryAmount) cabm.getBean();
		String msg = "Are you sure you wish to permanently remove " + "the category " + ca.getCategory().getName()
				+ " with the amount of $" + ca.getAmount() + "?";
		MessageBox.confirm("Delete category amount?", msg, new Listener<MessageBoxEvent>() {

			@Override
			public void handleEvent(MessageBoxEvent be) {
				Button button = be.getButtonClicked();

				if (button.getText().equals("Yes")) {

					categoryAmountStore.remove(cabm);
					// paycheckDetailsStore.findModel(paycheckCalc);
					updatePaycheckSummary();
					fireEvent(new AppEvent(AppEvents.CategoryAmountRemoved, ca));
				}

			}
		});

	}

	/** The new category amount. */
	private BeanModel newCategoryAmount = null;
	
	/** The all categories store. */
	private ListStore<BeanModel> allCategoriesStore;

	/**
	 * Handle add category amount button clicked.
	 */
	protected void handleAddCategoryAmountButtonClicked() {
		// TODO display error if there are no categories in the
		// allCategoriesStore.

		if (newCategoryAmount != null) {
			categoryAmountsGrid.getSelectionModel().select(newCategoryAmount, false);
			categoryAmountFormBindings.bind(newCategoryAmount);
			categoryComboBox.focus();

		} else {
			CategoryAmount ca = new CategoryAmount(paycheckCalc.getId());
			newCategoryAmount = BMF.getCategoryAmountFactory().createModel(ca);
			categoryAmountStore.add(newCategoryAmount);
			Record r = categoryAmountStore.getRecord(newCategoryAmount);
			// TODO maybe disable the form if there are no categories to add
			if (allCategoriesStore.getModels().size() > 0) {
				r.set("category", allCategoriesStore.getAt(0).getBean());
			}
			r.set("amount", 0.0d);

			// TODO do something about not allowing duplicates

			// this triggers a rebind, so we don't have to do it again
			categoryAmountsGrid.getSelectionModel().select(newCategoryAmount, false);
			enableCategoryAmountForm();
			categoryComboBox.focus();
			newCategoryAmount = null;
		}

	}

	/**
	 * Creates the category amount form.
	 *
	 * @return the form panel
	 */
	private FormPanel createCategoryAmountForm() {
		FormPanel panel = new FormPanel();
		panel.setHeaderVisible(false);

		categoryComboBox = new ComboBox<BeanModel>();
		categoryComboBox.setStore(allCategoriesStore);

		categoryComboBox.setFieldLabel("Category");
		categoryComboBox.setForceSelection(true);
		categoryComboBox.setAllowBlank(false);
		categoryComboBox.setEditable(false);
		categoryComboBox.setName("categoryName");
		categoryComboBox.setDisplayField("name");
		categoryComboBox.setTriggerAction(TriggerAction.ALL);
		panel.add(categoryComboBox);

		categoryAmountField = new NumberField();
		categoryAmountField.setName("amount");
		categoryAmountField.setFieldLabel("Amount");
		categoryAmountField.setAllowBlank(false);
		categoryAmountField.setAllowNegative(false);
		categoryAmountField.setAutoValidate(true);
		categoryAmountField.setFormat(NumberFormatter.CURRENCY_NUMBER_FORMAT);
		panel.add(categoryAmountField);

		categoryAmountFormBindings = new FormBinding(panel);
		FieldBinding categoryAmountFieldBinding = new FieldBinding(categoryComboBox, "category");
		categoryAmountFieldBinding.setConverter(new Converter() {

			@Override
			public Object convertFieldValue(Object value) {
				// Converts the field's value before being set on the model.
				// //after add, also onblur
				Object retVal = null;
				if (value != null) {
					BeanModel model = (BeanModel) value;
					retVal = model.getBean();
				}
				return retVal;
			}

			@Override
			public Object convertModelValue(Object value) {
				// Converts the model's value before being set on the field.
				// //on add, fires
				// TODO handle the case where we're rejecting changes and it's
				// null
				return value;
			}

		});
		categoryAmountFormBindings.addFieldBinding(categoryAmountFieldBinding);

		categoryAmountFormBindings.autoBind();
		categoryAmountFormBindings.setStore(categoryAmountsGrid.getStore());

		return panel;
	}

	/**
	 * Creates the category amounts grid.
	 *
	 * @return the grid
	 */
	private Grid<BeanModel> createCategoryAmountsGrid() {

		List<ColumnConfig> configs = new ArrayList<ColumnConfig>();

		ColumnConfig column = new ColumnConfig();

		column.setId("category");
		column.setHeader("Category");
		column.setDataIndex("category.name");

		column.setWidth(120);
		configs.add(column);

		column = new ColumnConfig();
		column.setId("amount");
		column.setHeader("Amount");
		column.setWidth(80);
		column.setNumberFormat(NumberFormatter.CURRENCY_NUMBER_FORMAT);
		column.setAlignment(HorizontalAlignment.RIGHT);
		configs.add(column);

		createCategoryAmountStore();
		ColumnModel cm = new ColumnModel(configs);

		Grid<BeanModel> grid = new Grid<BeanModel>(categoryAmountStore, cm);
		grid.getView().setEmptyText("No Categories Defined");
		grid.setBorders(true);
		// grid.setAutoExpandColumn("categoryName");
		grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		grid.getSelectionModel().addListener(Events.SelectionChange, new Listener<SelectionChangedEvent<BeanModel>>() {
			public void handleEvent(SelectionChangedEvent<BeanModel> be) {
				if (be.getSelection().size() > 0) {
					handlePaycheckSelected(be);
				} else {
					handlePaycheckSelectionCleared();
				}
			}

		});
		return grid;
	}

	/**
	 * Handles the <code>PaycheckSelectionCleared</code> event.
	 */
	private void handlePaycheckSelectionCleared() {
		categoryAmountFormBindings.unbind();
		deleteCategoryAmountButton.disable();
		disableCategoryAmountForm();
	}

	/**
	 * Handles the <code>PaycheckSelected</code> event.=
	 *
	 * @param be the selection event
	 */
	private void handlePaycheckSelected(SelectionChangedEvent<BeanModel> be) {
		// GWT.log("Binding category amount form");
		deleteCategoryAmountButton.enable();
		categoryAmountFormBindings.bind(be.getSelection().get(0));
		enableCategoryAmountForm();
	}

	/**
	 * Creates the category amount store.
	 */
	private void createCategoryAmountStore() {
		categoryAmountStore = new ListStore<BeanModel>();
		categoryAmountStore.setMonitorChanges(true);

		categoryAmountStore.addStoreListener(new StoreListener<BeanModel>() {
			@Override
			public void storeUpdate(StoreEvent<BeanModel> se) {
				if (se.getOperation() != null && se.getOperation().equals(Record.RecordUpdate.REJECT)) {
					updatePaycheckSummary();
				}
				if (se.getOperation() != null && se.getOperation().equals(Record.RecordUpdate.EDIT)) {
					updatePaycheckSummary();
				}
				if (se.getOperation() != null && se.getOperation().equals(Record.RecordUpdate.COMMIT)) {
					doBatchCategoryAmountCommit(se);
				}
			}
		});
	}

	/** The batch commit. */
	private List<CategoryAmount> batchCommit = new ArrayList<CategoryAmount>();

	/**
	 * Do batch category amount commit.
	 *
	 * @param se the se
	 */
	public void doBatchCategoryAmountCommit(StoreEvent se) {
		BeanModel bean = (BeanModel) se.getModel();
		batchCommit.add((CategoryAmount) bean.getBean());
		if (se.getStore().getModifiedRecords().size() == 0) {
			// call the batchService
			AppEvent e = new AppEvent(AppEvents.CategoryAmountsUpdated);
			e.setData("categoryAmounts", batchCommit);
			e.setData("id", paycheckCalc.getId());
			fireEvent(e);
			// clear the batch list for next time.
			batchCommit = new ArrayList<CategoryAmount>();
		}

	}

	/**/
	/**
	 * Creates the paycheck details form.
	 *
	 * @return the field set
	 */
	private FieldSet createPaycheckDetailsForm() {
		FieldSet fs = new FieldSet();
		fs.setHeading("Paycheck Details");
		FormPanel panel = new FormPanel();
		panel.setLabelWidth(100);
		panel.setHeaderVisible(false);
		panel.setBorders(false);

		nameField = new TextField<String>();
		nameField.setName("name");
		nameField.setAllowBlank(false);
		nameField.setMaxLength(16);
		nameField.setAutoValidate(true);
		nameField.setFieldLabel("Name");
		panel.add(nameField);

		estimatedAmountField = new NumberField();
		estimatedAmountField.setName("estimatedAmt");
		estimatedAmountField.setFieldLabel("Estimated Amount");
		estimatedAmountField.setAllowBlank(false);
		estimatedAmountField.setAllowNegative(false);
		estimatedAmountField.setAutoValidate(true);
		estimatedAmountField.setFormat(NumberFormatter.CURRENCY_NUMBER_FORMAT);
		estimatedAmountField.addListener(Events.Change, new Listener<FieldEvent>() {

			@Override
			public void handleEvent(FieldEvent be) {
				// GWT.log("Estimated Amount Changed");

			}

		});
		panel.add(estimatedAmountField);

		intervalComboBox = new SimpleComboBox<String>();
		for (Interval interval : Interval.values()) {
			intervalComboBox.add(interval.toString());
		}
		intervalComboBox.setFieldLabel("Paycheck Interval");
		intervalComboBox.setForceSelection(true);
		// intervalComboBox.setTypeAhead(true);
		intervalComboBox.setAllowBlank(false);
		intervalComboBox.setName("interval");
		intervalComboBox.setTriggerAction(TriggerAction.ALL);
		panel.add(intervalComboBox);

		descriptionField = new TextArea();
		descriptionField.setName("description");
		descriptionField.setFieldLabel("Description");
		panel.add(descriptionField);

		paycheckDetailsFormBindings = new FormBinding(panel);
		paycheckDetailsFormBindings.addFieldBinding(new SimpleComboBoxFieldBinding(intervalComboBox, "interval"));
		paycheckDetailsFormBindings.autoBind();
		paycheckDetailsFormBindings.setStore(paycheckDetailsStore);

		fs.add(panel);
		return fs;
	}

	/**
	 * Update editor view.
	 */
	private void updateEditorView() {
		// GWT.log("Updating Paycheck Calculator Editor View");
		if (paycheckCalc == null) {
			Dispatcher.get().fireEvent(AppEvents.Error);
		}
		paycheckCalc.addChangeListener(new ChangeListener() {

			@Override
			public void modelChanged(ChangeEvent event) {
				// GWT.log("Paycheck changed");
				updatePaycheckSummary();

			}

		});
		// update form bindings
		paycheckDetailsFormBindings.unbind();
		paycheckDetailsFormBindings.bind(paycheckCalc);

		// clear the store and then add new ones
		List<BeanModel> beans = BMF.getCategoryAmountFactory().createModel(paycheckCalc.getCategoryAmounts());

		// disable because nothing is selected by default
		deleteCategoryAmountButton.disable();

		categoryAmountFormBindings.unbind();
		categoryAmountStore.rejectChanges();
		categoryAmountStore.removeAll();
		categoryAmountStore.add(beans);

		// calculate new summary and fire event to controller
		updatePaycheckSummary();

	}

	/**
	 * Update paycheck summary total.
	 *
	 * @param num the num
	 */
	private void updatePaycheckSummaryTotal(Number num) {

	}

	/**
	 * Update paycheck summary.
	 */
	private void updatePaycheckSummary() {
		boolean useFormValue = true;
		PaycheckSummary summary = new PaycheckSummary();
		/*
		 * if(useFormValue){ double estimatedAmt = 0;
		 * if(estimatedAmountField.getValue() != null){
		 * estimatedAmountField.getValue().doubleValue(); }
		 * summary.setEstimatedAmt(estimatedAmt); }else{
		 */
		summary.setEstimatedAmt(paycheckCalc.getEstimatedAmt());
		/* } */
		List<BeanModel> categoryAmts = categoryAmountStore.getModels();

		double usedAmt = 0;
		for (BeanModel categoryAmount : categoryAmts) {
			CategoryAmount ca = (CategoryAmount) categoryAmount.getBean();
			usedAmt += ca.getAmount();
		}
		summary.setUsedAmt(usedAmt);
		fireEvent(new AppEvent(AppEvents.UpdateSummary, summary));
	}

	/* (non-Javadoc)
	 * @see com.extjs.gxt.ui.client.mvc.View#handleEvent(com.extjs.gxt.ui.client.mvc.AppEvent)
	 */
	@Override
	protected void handleEvent(AppEvent event) {
		if (event.getType() == AppEvents.PaycheckListLoaded) {
			onPaycheckListLoaded(event);
		}
		if (event.getType() == AppEvents.PaycheckCalcSelected) {
			onPaycheckSelected(event);
		}
		if (event.getType() == AppEvents.PaycheckCalcSelectionCleared) {
			paycheckDetailsFormBindings.unbind();
			disableForm();
		}
		if (event.getType() == AppEvents.CategoryAmountsUpdated) {
			List<CategoryAmount> categoryAmts = event.getData();
			categoryAmountStore.removeAll();
			categoryAmountStore.add(BMF.getCategoryAmountFactory().createModel(categoryAmts));
		}
		if (event.getType() == AppEvents.RefreshCategory) {
			GWT.log("RefreshCategory recieved in editor view");
			List<Category> categories = event.getData();
			populateAllCategoriesStore(categories);
			// paycheck may not be selected or initialized yet
			if (paycheckCalc != null) {
				AppEvent e = new AppEvent(AppEvents.CategoryAmountsUpdated);
				e.setData("categoryAmounts", null);
				e.setData("id", paycheckCalc.getId());
				GWT.log("Firing CategoryAmountsUpdated event with data in categoryAmounts and id");
				fireEvent(e);
			}
		}

	}

	/**
	 * Removes the stale category amounts.
	 * 
	 * @deprecated
	 */
	private void removeStaleCategoryAmounts() {

		// check modified records for a stale category
		List<Record> records = categoryAmountStore.getModifiedRecords();
		for (Record r : records) {
			BeanModel o = (BeanModel) r.get("category");
			Category c = (Category) o.getBean();
			boolean found = false;
			List<BeanModel> categories = allCategoriesStore.getModels();
			for (BeanModel model : categories) {
				if ((Long) model.get("id") == c.getId()) {
					found = true;
					if ((String) model.get("name") != c.getName()) {
						// the name was changed
						o.set("name", (String) model.get("name"));
					}
				}
			}
			if (!found) {
				r.reject(false);
			}
		}

		// check the models for a stale category
		List<BeanModel> models = categoryAmountStore.getModels();
		for (BeanModel beanModel : models) {
			BeanModel modelCategory = beanModel.get("category");
			CategoryAmount ca = (CategoryAmount) beanModel.getBean();
			boolean found = false;
			List<BeanModel> categories = allCategoriesStore.getModels();
			for (BeanModel model : categories) {
				if ((Long) model.get("id") == ca.getCategory().getId()) {
					found = true;
					if ((String) model.get("name") != ca.getCategory().getName()) {
						// the name was changed
						modelCategory.set("name", ca.getCategory().getName());

					}
				}
			}
			if (found == false) {
				categoryAmountStore.remove(beanModel);
			}
		}
	}

	/**
	 * On paycheck selected.
	 *
	 * @param event the event
	 */
	private void onPaycheckSelected(AppEvent event) {
		Object data = event.getData();
		if (data == null || !(data instanceof PaycheckCalculator)) {
			Dispatcher.get().fireEvent(AppEvents.Error);
		} else {
			paycheckCalc = (PaycheckCalculator) data;
			enableForm();
			updateEditorView();
		}

	}

}
